#include "Spi.h"

void
spi_init(Spi *self, SpiType s_type, uint8_t spi_choose)
{
        /* GPIO 初始化，数组：NSS、SCK、MISO、MOSI */
        GPIO_InitTypeDef gpio[3];
        gpio[0].GPIO_Speed = GPIO_Speed_50MHz;
        gpio[0].GPIO_Mode  = GPIO_Mode_Out_PP;
        gpio[0].GPIO_Pin   = 0;
        gpio[1].GPIO_Speed = GPIO_Speed_50MHz;
        gpio[1].GPIO_Mode  = GPIO_Mode_AF_PP;
        gpio[1].GPIO_Pin   = 0;
        gpio[2].GPIO_Speed = GPIO_Speed_50MHz;
        gpio[2].GPIO_Mode  = GPIO_Mode_IPU;

        /* SPI 初始化 */
        SPI_InitTypeDef spi = {.SPI_Mode      = SPI_Mode_Master,
                               .SPI_Direction = SPI_Direction_2Lines_FullDuplex,
                               .SPI_DataSize  = SPI_DataSize_8b,
                               .SPI_FirstBit  = SPI_FirstBit_MSB,
                               .SPI_BaudRatePrescaler =
                                       SPI_BaudRatePrescaler_128,
                               .SPI_CPOL          = SPI_CPOL_Low,
                               .SPI_CPHA          = SPI_CPHA_1Edge,
                               .SPI_NSS           = SPI_NSS_Soft,
                               .SPI_CRCPolynomial = 7};

        switch (s_type) {
        case SPI_TYPE_SPI1:
                self->spi  = SPI1;
                self->gpio = GPIOA;
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
                if (spi_choose & SPI_CHOOSE_NSS)
                        gpio[0].GPIO_Pin = GPIO_Pin_4;
                if (spi_choose & SPI_CHOOSE_SCK)
                        gpio[1].GPIO_Pin = GPIO_Pin_5;
                if (spi_choose & SPI_CHOOSE_MISO)
                        gpio[2].GPIO_Pin = GPIO_Pin_6;
                if (spi_choose & SPI_CHOOSE_MOSI)
                        gpio[1].GPIO_Pin |= GPIO_Pin_7;
                break;
        case SPI_TYPE_SPI2:
                self->spi  = SPI2;
                self->gpio = GPIOB;
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
                RCC_APB2PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
                if (spi_choose & SPI_CHOOSE_NSS)
                        gpio[0].GPIO_Pin = GPIO_Pin_12;
                if (spi_choose & SPI_CHOOSE_SCK)
                        gpio[1].GPIO_Pin = GPIO_Pin_13;
                if (spi_choose & SPI_CHOOSE_MISO)
                        gpio[2].GPIO_Pin = GPIO_Pin_14;
                if (spi_choose & SPI_CHOOSE_MOSI)
                        gpio[1].GPIO_Pin |= GPIO_Pin_15;
                break;
        }

        if (spi_choose & SPI_CHOOSE_NSS) {
                self->pin_nss = gpio[0].GPIO_Pin;
                GPIO_Init(self->gpio, &gpio[0]);
        }
        if (spi_choose & (SPI_CHOOSE_SCK | SPI_CHOOSE_MOSI))
                GPIO_Init(self->gpio, &gpio[1]);
        if (spi_choose & SPI_CHOOSE_MISO)
                GPIO_Init(self->gpio, &gpio[2]);
        SPI_Init(self->spi, &spi);
        SPI_Cmd(self->spi, ENABLE);

        GPIO_WriteBit(self->gpio, self->pin_nss, (BitAction)1);
}

void
spi_start(Spi *self)
{
        GPIO_WriteBit(self->gpio, self->pin_nss, (BitAction)0);
}

void
spi_stop(Spi *self)
{
        GPIO_WriteBit(self->gpio, self->pin_nss, (BitAction)1);
}

inline uint8_t
spi_send_and_receive(Spi *self, uint8_t byte)
{
        while (SPI_I2S_GetFlagStatus(self->spi, SPI_I2S_FLAG_TXE) != SET)
                ;
        SPI_I2S_SendData(self->spi, byte);
        while (SPI_I2S_GetFlagStatus(self->spi, SPI_I2S_FLAG_RXNE) != SET)
                ;
        return SPI_I2S_ReceiveData(self->spi);
}
